module.exports=new (function(){

    this.getHead=function(){
        return `
package  sophia.mmorpg.proto;

import org.apache.mina.core.buffer.IoBuffer;
import sophia.foundation.communication.core.ActionEventBase;
import java.nio.charset.Charset;
import java.util.ArrayList;

`;
    }

    this.space_def = '    ';

    this.getContentHead=function(name){
        var result="";
        result+=`public class ${name} extends ActionEventBase  {\n`;
        return result;
    }

    this.genProperty=function(javatype, propertyName, neednew) {
        var startSpace = this.space_def;
        var result = startSpace + '//m_' + propertyName + '\n';

        if(neednew)
        {
            result += startSpace + 'private '+ javatype +' m_' + propertyName + ' = new ' + javatype + '();\n';
        }
        else
        {
            result += startSpace + 'private '+ javatype +' m_' + propertyName + ';\n';
        }

        result += startSpace + 'public '+ javatype +' get' + propertyName + '(){\n';
        result += startSpace + this.space_def + 'return m_' + propertyName + ';\n';
        result += startSpace + '}\n';
        result += startSpace + 'public void set' + propertyName + '('+ javatype +' value){\n';
        result += startSpace + this.space_def + 'm_' + propertyName + ' = value;\n';
        result += startSpace + '}\n\n'; 

        return result;
    }

    this.getContent=function(name,fileds){
		//trim begin
		for(var filed of fileds){
			filed.type = filed.type.replace(/[\r\n\t]/g,"")
			filed.propertyName = filed.propertyName.replace(/[\r\n\t]/g,"")
			filed.propertyType = filed.propertyType.replace(/[\r\n\t]/g,"")
		}
		//trim end
		
        var result='';
        ////////////////////////////////////////////////   
        for(var filed of fileds){
            
                var isArray = (filed.type=='repeated');
                switch(filed.propertyType)
                {
                    case 'byte':
                        result+=this.genProperty(isArray?'ArrayList<byte>':'byte', filed.propertyName, isArray);
                        break;
                    case 'string':
                        result+=this.genProperty(isArray?'ArrayList<String>':'String', filed.propertyName, isArray);
                        break;
                    case 'bool':
					case 'boolean':
                        result+=this.genProperty(isArray?'ArrayList<Boolean>':'Boolean', filed.propertyName, isArray);
                        break;
                    case 'double':
                        result+=this.genProperty(isArray?'ArrayList<double>':'double', filed.propertyName, isArray);
                        break;
                    case 'float':
                        result+=this.genProperty(isArray?'ArrayList<float>':'float', filed.propertyName, isArray);
                        break;
                    case 'int32':
                    case 'int64':
                        result+=this.genProperty(isArray?'ArrayList<Integer>':'int', filed.propertyName, isArray);
                        break;
                    case 'uint32':
                    case 'uint64':
                        result+=this.genProperty(isArray?'ArrayList<Integer>':'int', filed.propertyName, isArray);
                        break;
                    case 'sint32':
                        result+=this.genProperty(isArray?'ArrayList<short>':'short', filed.propertyName, isArray);
                        break;
                    case 'sing64'://没有，所以32位
                        result+=this.genProperty(isArray?'ArrayList<Integer>':'int', filed.propertyName, isArray);
                        break;
                    case 'fixed32':
                    case 'fixed64':
                    case 'sfixed32':
                    case 'sfixed64':
                        result+=this.genProperty(isArray?'ArrayList<Integer>':'int', filed.propertyName, isArray);
                        break;
                    default:
                        result+=this.genProperty(isArray?'ArrayList<'+filed.propertyType+'>': filed.propertyType, filed.propertyName, true);
                        break;
                }
        }

        //////////////////////////////////////////////// 
        result += this.space_def + '@Override\n';
        result += this.space_def + 'public IoBuffer packBody(IoBuffer buffer) {\n';
        result += this.space_def + 'try{\n';
		result += this.space_def + this.space_def + '@SuppressWarnings("unused")\n';
		result += this.space_def + this.space_def + 'int total= 0;\n';		

        function getWriteSigle(filed,lastSpace,isArray){
            var space = lastSpace;
            var result='';
            result += space + '//m_'+filed.propertyName+'\n';

            var opVarName = 'this.m_'+filed.propertyName;
            if(isArray)
            {
                opVarName = 'this.m_'+filed.propertyName+'.get(i)';
            }

            switch(filed.propertyType){
                case 'byte':
                    result += space + 'buffer.put((byte)'+opVarName+');\n';
                    break;
                case 'string':
					if(!isArray)
					{
						result += space + 'if( '+ opVarName +' == null ) ' + opVarName + ' = "";\n'
					}
					
                    result += space + 'buffer.putShort((short)'+opVarName+'.getBytes("UTF-8").length);\n';
                    result += space + 'buffer.put('+opVarName+'.getBytes("UTF-8"));\n';
                    break;
                case 'bool':
				case 'boolean':
                    result += space + 'buffer.put((byte)'+opVarName+');\n';
                    break;
                case 'double':
                    result += space + 'buffer.putDouble('+opVarName+');\n'; 
                    break;
                case 'float':
                    result += space + 'buffer.putFloat('+opVarName+');\n';
                    break;
                case 'int32':
                case 'int64':
                    result += space + 'buffer.putInt('+opVarName+');\n';
                    break;
                case 'uint32':
                case 'uint64':
                    result += space + 'buffer.putInt('+opVarName+');\n';
                    break;
                case 'sint32': 
                    result += space + 'buffer.putShort('+opVarName+');\n';
                    break;
                case 'sing64':
                    result += space + 'buffer.putInt('+opVarName+');\n';
                    break;
                case 'fixed32':
                case 'fixed64':
                case 'sfixed32':
                case 'sfixed64':
                    result += space + 'buffer.putInt('+opVarName+');\n';
                    break;
                default:
                    result += space + opVarName + '.packBody(buffer);\n';
                    break;
            }
            result += '\n';
            return result;
        }


        for(var filed of fileds){
            var startSpace = this.space_def + this.space_def;
            if(filed.type=='repeated'){
                result += startSpace + `total=this.m_${filed.propertyName}!=null?this.m_${filed.propertyName}.size():0;\n`
                result += startSpace + `buffer.putShort((short)total);\n`
                result += startSpace + `if(total > 0){\n`
                result += startSpace + this.space_def + `for(short i=0;i<total;i++){\n`
                result += getWriteSigle(filed,startSpace + this.space_def + this.space_def, true);
                result += startSpace + this.space_def + `}\n`
                result += startSpace + `};\n`
            }else{
                result+=getWriteSigle(filed,startSpace, false);
            }
        }
        result += this.space_def + '}catch(Exception e){\n';
        result += this.space_def + this.space_def + 'e.printStackTrace();\n';
        result += this.space_def + '}\n';
        result += '\n';

        result += this.space_def + this.space_def + 'return buffer;\n';
        result += this.space_def + `};\n\n`;
        //////////////////////////////////////////////// 
        result += this.space_def + '@Override\n';
        result += this.space_def + 'public void unpackBody(IoBuffer buffer) {\n';
		result += this.space_def + this.space_def + '@SuppressWarnings("unused")\n';
		result += this.space_def + this.space_def + 'int total= 0;\n';	
		
        function getReadSigle(filed,lastSpace,isArray){
            var space=lastSpace;
            var result='';
            var space_next = "    ";
            result += space + '//m_'+filed.propertyName+'\n';

            var opVarName = 'm_'+filed.propertyName;
            if(isArray)
            {
                opVarName = 'tmp'+filed.propertyName;
            }

            switch(filed.propertyType){
                case 'byte':
                    result += space + `${opVarName}=buffer.get();\n`;
                    break;
                case 'string':
                    result += space + `${opVarName}=getStringFromBuf(buffer);\n`;
                    break;
                case 'bool':
				case 'boolean':
                    result += space + `${opVarName}=(Boolean)buffer.get();\n`;
                    break;
                case 'double':
                    result += space + `${opVarName}=buffer.getDouble();\n`;
                    break;
                case 'float':
                    result += space + `${opVarName}=buffer.getFloat();\n`;
                    break;
                case 'int32':
                case 'int64':
                    result += space + `${opVarName}=buffer.getInt();\n`;
                    break;
                case 'uint32':
                case 'uint64':
                    result += space + `${opVarName}=buffer.getInt();\n`;
					result += space + `if(${opVarName}<0) ${opVarName}=0;\n`;
                    break;
                case 'sint32':
                    result += space + `${opVarName}=buffer.getShort();\n`;
                    break;
                case 'sing64':
                    result += space + `${opVarName}=buffer.getInt();\n`;
                    break;
                case 'fixed32':
                case 'fixed64':
                case 'sfixed32':
                case 'sfixed64':
                    result += space + `${opVarName}=buffer.getInt();\n`;
                    break;
                default:
                    if(isArray)
                    {
                        result += space + opVarName + ' = new ' + filed.propertyType + '();\n';
                    }
                    result += space + opVarName +'.unpackBody(buffer);\n';
                    break;
            }

            result += '\n';
            return result;
        }
        for(var filed of fileds){
            var startSpaceUpk = this.space_def + this.space_def;
            if(filed.type=='repeated'){
                result += startSpaceUpk + `total=buffer.getShort();\n`
                result += startSpaceUpk + `if(total > 0){\n`;
                result += startSpaceUpk + this.getType(filed.propertyType) + ' '+ 'tmp' + filed.propertyName + ';\n';
                result += startSpaceUpk + 'this.m_'+filed.propertyName + '.clear();\n';
                result += startSpaceUpk + this.space_def + `while(total-- > 0){\n`;
                result += getReadSigle(filed,startSpaceUpk + this.space_def + this.space_def,true);
                result += startSpaceUpk + this.space_def + this.space_def + 'this.m_'+filed.propertyName + '.add('+ 'tmp'+filed.propertyName +');\n';
                result += startSpaceUpk + this.space_def + `}\n`
                result += startSpaceUpk + `}\n`
            }else{
                result += getReadSigle(filed,startSpaceUpk, false);
            }
        }
        result += this.space_def + '}\n\n';
		
		//重载name函数
		result += this.space_def + '@Override\n';
		result += this.space_def + 'public String getName() {\n';
		result += this.space_def + this.space_def + 'return "'+ name +'";\n';
		result += this.space_def + '}\n\n';

        //辅助函数
		result += this.space_def + '@SuppressWarnings("unused")\n';
        result += this.space_def + 'private String getStringFromBuf(IoBuffer bufferIn){\n';
        result += this.space_def + this.space_def +'String ret = "";\n';
        result += this.space_def + this.space_def +'try {\n';
        result += this.space_def + this.space_def + this.space_def + 'short str_len = bufferIn.getShort();\n';
        result += this.space_def + this.space_def + this.space_def + 'byte[] str_content = new byte[str_len];\n';
        result += this.space_def + this.space_def + this.space_def + 'bufferIn.get(str_content, bufferIn.arrayOffset(), str_len);\n';
        result += this.space_def + this.space_def + this.space_def + `ret=IoBuffer.wrap(str_content).getString(Charset.forName("UTF-8").newDecoder());\n`;
        result += this.space_def + this.space_def + '} catch (Exception e1) {\n';
        result += this.space_def + this.space_def + this.space_def + 'e1.printStackTrace();\n';
        result += this.space_def + this.space_def + '}\n';
        result += this.space_def + 'return ret;\n}\n\n';


        return result;
    }

    this.getContentEnd=function(name){
        var result="}\n\n\n\n";
        return result;
    }

    this.getEnd=function(){
        return `})(p || (p = {}));`;
    }
    
    this.getType=function(type){
        switch(type){
            case 'byte':
                return "byte";
            case 'string':
                return "String";
            case 'bool':
			case 'boolean':
                return "Boolean";
            case 'double':
                return "Double";
            case 'float':
                return "float";
            case 'int32':
                return "int";
            case 'uint32':
                return "int";
            case 'int64':
                return "int";
            case 'uint64':
                return "int";
            case 'sint32':
                return "short";
            case 'sing64':
                return "int";
            case 'fixed32':
            case 'fixed64':
            case 'sfixed32':
            case 'sfixed64':
                return "int";
        }
        return type;
    }
})()